using System.Collections.Generic;
using System.Text;

namespace NFreeMarker.Core
{
    /**
     * An instruction that contains one or more assignments
     */
    internal sealed class AssignmentInstruction : TemplateElement
    {
        private readonly AssignmentScope _scope;
        private Expression _namespaceExp;

        internal AssignmentInstruction(AssignmentScope scope)
        {
            _scope = scope;
            NestedElements = new List<TemplateElement>(1);
        }

        internal void AddAssignment(Assignment ass)
        {
            NestedElements.Add(ass);
        }

        internal void SetNamespaceExp(Expression namespaceExp)
        {
            _namespaceExp = namespaceExp;
            foreach (Assignment nestedElement in NestedElements)
            {
                nestedElement.SetNamespaceExp(namespaceExp);
            }
        }

        internal override void Accept(Environment env)
        {
            foreach (Assignment ass in NestedElements)
            {
                env.Visit(ass);
            }
        }

        public override string GetCanonicalForm()
        {
            string tag = "<#local ";
            switch (_scope)
            {
                case AssignmentScope.Global:
                    tag = "<#global ";
                    break;
                case AssignmentScope.Namespace:
                    tag = "<#assign ";
                    break;
            }
            var buf = new StringBuilder(tag);
            for (int i = 0; i < NestedElements.Count; i++)
            {
                var ass = (Assignment) NestedElements[i];
                buf.Append(ass.GetCanonicalForm());
                if (i < NestedElements.Count - 1)
                {
                    buf.Append(" ");
                }
            }
            if (_namespaceExp != null)
            {
                buf.Append(" in ");
                buf.Append(_namespaceExp.GetCanonicalForm());
            }
            buf.Append("/>");
            return buf.ToString();
        }

        public override string GetDescription()
        {
            string tag = "local ";
            switch (_scope)
            {
                case AssignmentScope.Global:
                    tag = "global ";
                    break;
                case AssignmentScope.Namespace:
                    tag = "assign ";
                    break;
            }
            tag += "assignment";
            if (NestedElements.Count > 1)
            {
                tag += "s";
            }
            return tag;
        }

        internal override TemplateElement PostParseCleanup(bool stripWhitespace)
        {
            base.PostParseCleanup(stripWhitespace);
            if (NestedElements.Count == 1)
            {
                var ass = (Assignment) NestedElements[0];
                ass.SetLocation(GetTemplate(), this, this);
                return ass;
            }
            return this;
        }
    }
}